/*
 * Copyright (c) Huawei Technologies Co., Ltd. 2025-2025. All rights reserved.
 *
 */

import { FileSet, MetricLogType, SubmitOption, TaskDetails, TaskState } from '@ohos/hvigor';
import fse from 'fs-extra';
import path from 'path';

import { BuildArtifactExtension } from '../const/build-directory-const.js';
import { CommonConst } from '../const/common-const.js';
import { SignTypeEnum } from '../enum/sign-type-enum.js';
import { ProjectBuildProfile } from '../options/build/project-build-profile.js';
import { OhosLogger } from '../utils/log/ohos-logger.js';
import { getRemoteHspObj } from '../utils/remote-hsp-utils.js';

import { BaseSign } from './base/base-sign.js';
import { GlobalProjectDataService } from './service/global-project-data-service.js';
import { TargetTaskService } from './service/target-task-service.js';
import { SignModel } from './sign/command-builder-impl/sign-model.js';
import { runSign } from './worker/sign-job.js';
import RemoteHspOpt = ProjectBuildProfile.RemoteHspOpt;
import { isSigned } from './sign/sign-util.js';
import { Dependency } from '../project/dependency/core/dependency-interface.js';

export interface SignConfig {
  // 签名命令
  signCommand: string[];

  // 模块名
  moduleName: string;

  // 签名类型
  signType: SignTypeEnum;

  bundleName: string;

  // 签名p7b文件校验命令
  verifySignCommands: string[];
}

export abstract class SignRemoteHsp extends BaseSign {
  // 工程级远程hsp的SignModel列表，用于签名
  protected readonly allProjectSignedRemoteHspList: SignModel[] = [];

  // 模块级远程hsp的SignModel列表，用于签名
  protected readonly allModuleSignedRemoteHspList: SignModel[] = [];

  // 需要签名的远程hsp文件，用于生成signRemoteHspList
  protected readonly allProjectRequiredSignRemoteHspMap: Map<string, RemoteHspOpt> = new Map<string, RemoteHspOpt>();

  // 需要签名的远程hsp文件，用于生成signRemoteHspList
  protected readonly allModuleRequiredSignRemoteHspMap: Map<string, RemoteHspOpt> = new Map<string, RemoteHspOpt>();

  // 工程目录下需要签名的远程hsp路径list
  protected readonly allProjectHspPathList: string[] = [];

  // 模块目录下需要签名的远程hsp路径list
  protected readonly allModuleHspPathList: string[] = [];

  // 工程目录下oh_modules中远程hsp路径list
  protected readonly allProjectRemoteHspPathList: string[] = [];

  // 模块目录下oh_modules中远程hsp路径list
  protected readonly allModuleRemoteHspPathList: string[] = [];

  protected readonly projectRemoteHspCachePath: string;

  protected readonly _log: OhosLogger = OhosLogger.getLoggerWithDurationId(SignRemoteHsp.name, this.durationEvent.getId());

  protected constructor(targetService: TargetTaskService, taskDetails: TaskDetails, signType?: SignTypeEnum) {
    super(targetService, taskDetails, signType);
    const projectHspDir = this.projectModel.getCacheRemoteHspPath(this.targetData.getProduct().name);
    this.projectRemoteHspCachePath = path.resolve(projectHspDir, CommonConst.REMOTE_HSP_CACHE);
  }

  protected async doTaskAction() {
    // no action
  }

  declareInputFiles(): FileSet {
    const fileSet = super.declareInputFiles();
    if (this.projectRemoteHspCachePath && fse.existsSync(this.projectRemoteHspCachePath)) {
      fileSet.addEntry(this.projectRemoteHspCachePath, { isDirectory: false });
    }
    return fileSet;
  }

  /**
   * 获取工程级需要签名的remoteHspMap
   * @param remoteHspPath
   * @param npmDependencies
   * @protected
   */
  protected getProjectSignRemoteHspMap(remoteHspPath: string, npmDependencies: Dependency[]) {
    if (!fse.existsSync(remoteHspPath)) {
      return;
    }
    const hspModules = fse.readdirSync(remoteHspPath);
    for (const hspDirItem of hspModules) {
      const hspDirPath = path.resolve(remoteHspPath, hspDirItem);
      const currentRemoteHspObj: RemoteHspOpt | undefined = getRemoteHspObj(hspDirPath, hspDirItem, this.log);
      if (currentRemoteHspObj) {
        npmDependencies.forEach( dependencies => {
          if(dependencies.getPackageName() === currentRemoteHspObj.hspName) {
            this.allProjectRequiredSignRemoteHspMap.set(currentRemoteHspObj.hspFileName, { ...currentRemoteHspObj });
          }
        });
      }
    }
  }

  /**
   * 如果不存在remoteHspCache.json文件，则新建文件夹并赋值空对象
   * @private
   */
  protected createProjectRemoteHspCache() {
    if (!isSigned(this.projectModel)) {
      return;
    }
    if (!fse.existsSync(this.projectRemoteHspCachePath)) {
      fse.createFileSync(this.projectRemoteHspCachePath);
      fse.writeJsonSync(this.projectRemoteHspCachePath, {});
    }
  }

  /**
   * 获取模块级级需要签名的remoteHspMap
   * @param remoteHspPath
   * @param npmDependencies
   * @protected
   */
  protected getModuleSignRemoteHspMap(remoteHspPath: string, npmDependencies: Dependency[]) {
    if (!fse.existsSync(remoteHspPath)) {
      return;
    }
    const hspModules = fse.readdirSync(remoteHspPath);
    for (const hspDirItem of hspModules) {
      const hspDirPath = path.resolve(remoteHspPath, hspDirItem);
      const currentRemoteHspObj: RemoteHspOpt | undefined = getRemoteHspObj(hspDirPath, hspDirItem, this.log);
      if (currentRemoteHspObj) {
        npmDependencies.forEach( dependencies => {
          if(dependencies.getPackageName() === currentRemoteHspObj.hspName) {
            this.allModuleRequiredSignRemoteHspMap.set(currentRemoteHspObj.hspFileName, { ...currentRemoteHspObj });
          }
        });
      }
    }
  }

  /**
   * 初始化需要签名的list信息
   *
   * @param allOhpmHspPathList  oh_mudules的签名路径list
   * @param allSignedHspPathList  工程级Build-Cache目录下即将签名的hsplist
   * @param allHspSignModelList   需要签名的远程hsp签名信息list
   * @param allRequiredSignRemoteHspMap  所有需要签名的远程hsp信息map
   * @protected
   */
  protected initAllSignRemoteHspList(
    allSignedHspPathList: string[],
    allOhpmHspPathList: string[],
    allHspSignModelList: SignModel[],
    allRequiredSignRemoteHspMap: Map<string, RemoteHspOpt>,
  ) {
    const signType = this.targetData.isHarmonyOS() ? SignTypeEnum.HOS_HAP : SignTypeEnum.HAP;
    const projectHspDir = this.projectModel.getCacheRemoteHspPath(this.targetData.getProduct().name);
    allRequiredSignRemoteHspMap.forEach((item) => {
      const hspFileName = item.hspFileName;
      const hspPath = item.hspPath;
      const hspDirName = item.hspDirName;
      const signedHspName = hspFileName.replace(BuildArtifactExtension.DOT_HSP, `-signed${BuildArtifactExtension.DOT_HSP}`);
      const signedHspPath = path.resolve(projectHspDir, hspDirName, signedHspName);
      if (GlobalProjectDataService.getInstance().needSignedRemoteHsp(hspDirName, this.moduleModel.getName())) {
        const integratedRemoteHspPath = this.projectModel.getCacheIntegratedHspPath(this.targetData.getProduct().name);
        const inputPath = item.isIntegratedHsp ? path.resolve(integratedRemoteHspPath, hspDirName, hspFileName) : hspPath;
        allOhpmHspPathList.push(inputPath);
        allSignedHspPathList.push(signedHspPath);
        allHspSignModelList.push(new SignModel(signType, inputPath, signedHspPath));
        GlobalProjectDataService.getInstance().setNeedSignedRemoteHspMap(hspDirName, {
          hspFileName: hspFileName,
          hspDirName: hspDirName,
          version: item.hspVersion,
          hspPath: inputPath,
          signedHspPath: signedHspPath,
          isSigned: false,
        });
      }
    });
  }

  protected initDefaultSignConfig(signOhpmModel: SignModel, signCommand: string[], verifySignCommands: string[]): SignConfig {
    return {
      signCommand: signCommand,
      moduleName: this.service.getModuleModel().getName(),
      signType: signOhpmModel.getSignType(),
      bundleName: this.signUtil.getBundleNameFromHap(this.projectModel),
      verifySignCommands: verifySignCommands,
    };
  }

  /**
   * 提交签名任务到worker进程
   *
   * @param signOhpmModel  signModel签名信息
   * @param callback  worker执行后的回调函数
   * @protected
   */
  protected async submitSignWorker(signOhpmModel: SignModel, callback: Function) {
    const signCommand = this.signUtil.getSignCommand(signOhpmModel);
    const verifySignCommands = this.signUtil.getVerifySignCommands(this.targetData.getPathInfo());
    if (!signCommand || !verifySignCommands) {
      this._log.debug('No signCommand, please check sign info.');
      return;
    }
    const config: SignConfig = this.initDefaultSignConfig(signOhpmModel, signCommand, verifySignCommands);
    const script: string = path.resolve(__dirname, './worker/sign-job.js/runSign');
    const options: SubmitOption = {
      workInput: config,
      callback: callback,
    };
    if (!fse.existsSync(signOhpmModel.getOutPutFilePath())) {
      fse.mkdirSync(path.dirname(signOhpmModel.getOutPutFilePath()), { recursive: true });
    }
    if (this.getWorkerPool().submit(this, script, options).getState() === TaskState.REJECT) {
      const executeTaskName = 'sign remote hsp';
      const subExecuteDurationEvent = this.durationEvent.createSubEvent(executeTaskName, '');
      subExecuteDurationEvent.start();
      this._log.debug('Worker dispatch failed, running native strip on main thread.');
      await this.signUtil.validateBundleName(signOhpmModel, this.targetData.getPathInfo(), subExecuteDurationEvent);
      await runSign(config);
      subExecuteDurationEvent.stop();
      subExecuteDurationEvent.setLog(executeTaskName, MetricLogType.INFO);
    }
  }

  protected signRemoteHspCallBack(projectRemoteHspCachePath: string, signedHspPath: string) {
    GlobalProjectDataService.getInstance().changeRemoteHspSigned(signedHspPath);
    if (GlobalProjectDataService.getInstance().allRemoteHspSigned()) {
      const remoteHspCache = GlobalProjectDataService.getInstance().getRemoteHspCache();
      fse.writeJsonSync(projectRemoteHspCachePath, {
        signingConfig: remoteHspCache.signingConfig,
        signedRemoteHsps: Object.fromEntries(remoteHspCache.signedRemoteHsps),
      });
    }
  }

  initTaskDepends(): void {
    // no tasks
  }
}
